Factors Determining Urban Growth (2)#
The previous section collected data on the factors that we believe to determine urban growth. In this section, we will make spatial lags for population and land cover factors. This is an important difference of spatial models like this from other non-spatial models.
Lag population density: Urban growth is more likely to occur not just in currently dense locations, but near these dense locations.
Lag land cover: Urban growth is more likely to occur around existing urbanized areas, as this provides greater access to urban infrastructure and other amenities.
We achieved this by calculating the average population density and ratio of developed cells for each cell’s queen neighbors. A cell’s queen neighbors are defined as any cell that shares a vertex or an edge with the cell, as shown on the right in the below diagram.

Show code cell content
# The scripts in this section should be run in the environment dictated by requirements-pysal.txt
import numpy as np
import pandas as pd
import geopandas as gpd
from pysal.lib import weights
crs = "EPSG:2232"
# Read in the data where we left off last time
fishnet = gpd.read_file("../data/fishnets/with_distance.geojson")
fishnet.crs = crs
def get_lag_developed(fishnet, to_lag_column, new_column_name):
w_queen = weights.Queen.from_dataframe(fishnet)
w_queen.transform = "r"
binary = fishnet[to_lag_column].astype(int)
lag = weights.lag_spatial(w_queen, binary)
fishnet[new_column_name] = lag
return fishnet
for year in [2009, 2019]:
fishnet = get_lag_developed(
fishnet,
to_lag_column=f"developed_{year}",
new_column_name=f"lag_developed_{year}",
)
for year in [2010, 2020]:
fishnet = get_lag_developed(
fishnet,
to_lag_column=f"population_{year}",
new_column_name=f"lag_population_{year}",
)
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In[1], line 5
3 import pandas as pd
4 import geopandas as gpd
----> 5 from pysal.lib import weights
7 crs = "EPSG:2232"
9 # Read in the data where we left off last time
ModuleNotFoundError: No module named 'pysal'
The below maps shows the spatial lags of population density and developed land.
Show code cell source
import altair as alt
alt.data_transformers.disable_max_rows()
def altair_fishnet_gradient(
fishnet, column, legend_title, title, scheme="purples", reversed=False
):
chart = (
alt.Chart(fishnet.to_crs(4326)[["geometry", column]])
.mark_geoshape()
.encode(
color=alt.Color(
f"{column}:Q",
title=legend_title,
scale=alt.Scale(
scheme=scheme,
reverse=reversed,
),
)
)
.properties(width=400, height=330, title=title)
)
return chart
left = altair_fishnet_gradient(
fishnet=fishnet,
column="lag_population_2010",
legend_title="Population",
title="Average population of surrounding cells in 2010",
)
right = altair_fishnet_gradient(
fishnet=fishnet,
column="lag_population_2020",
legend_title="Population",
title="Average population of surrounding cells in 2020",
)
left | right
Show code cell source
left = altair_fishnet_gradient(
fishnet=fishnet,
column="lag_developed_2009",
legend_title="Ratio",
title="Ratio of surrounding cells developed in 2010",
)
right = altair_fishnet_gradient(
fishnet=fishnet,
column="lag_developed_2019",
legend_title="Ratio",
title="Ratio of surrounding cells developed in 2010",
)
left | right
Other than that, urban growth patterns may differ by administrative boundaries. The below map shows the 10 counties in the Denver MSA.
Show code cell source
from pygris import counties
ten_counties = ["001", "005", "031", "035", "014", "039", "059", "093", "019", "047"]
msa = (
counties(state="08", year=2020)
.query("COUNTYFP.isin(@ten_counties)")
.copy()[["NAME", "geometry"]]
)
msa = msa.to_crs(crs)
fishnet["centroid"] = fishnet.geometry.centroid
# Identify which county each cell is in
fishnet = (
gpd.sjoin(fishnet.set_geometry("centroid"), msa, how="left", predicate="within")
.drop(columns=["index_right", "centroid"])
.set_geometry("geometry").rename(columns={"NAME": "county"})
)
def altair_fishnet(fishnet, column, legend_title, title):
chart = alt.Chart(
fishnet.to_crs(4326)[["geometry", column]]
).mark_geoshape().encode(
color=alt.Color(
f"{column}:N",
title=legend_title,
)
).properties(
width=400, height=330, title=title
)
return chart
altair_fishnet(
fishnet=fishnet.dropna(subset=["county"]),
column="county",
legend_title="County",
title="Counties in the Denver MSA",
)